package eu.goldenak.ircbot;

import java.io.IOException;
import java.util.HashMap;

/**
 * This class manages all the connections currently open to IRC servers. We call
 * these connections bots because it's shorter. But this whole program, no 
 * matter how much connections is one bot too. I like a bit of confusion.
 */
public class BotManager extends Thread {
	
	/**
	 * The only instance to this object.
	 */
	private static final BotManager s_pInstance = new BotManager ();
	
	/**
	 * All bots ever created are stored in this BotGroup.
	 */
	private BotGroup m_pBots;
	
	/**
	 * Constructor, which prepares the main BotGroup where all bots in this
	 * program will reside in.
	 */
	private BotManager() {
		m_pBots = new BotGroup (Integer.parseInt (
			ConfigManager.getModule ("Main").get ("numbots")
		));
		
		// Register shutdown hook.
		Runtime.getRuntime ().addShutdownHook (new Thread () {
			public void run () {
				BotManager.getInstance ().shutdown ();
				
				try {
					Thread.sleep (2000);
				} catch (InterruptedException pException) {}
			}
		});
	}
	
	/**
	 * Since all bots are managed in here, we have to be sure we have only one
	 * instance of the BotManager floating around in our program. Singleton
	 * ensures this for us.
	 */
	public static synchronized BotManager getInstance () {
		return s_pInstance;
	}
	
	/**
	 * Returns a pointer to the BotGroup containing all bots.
	 */
	public BotGroup getBots() {
		return m_pBots;
	}
	
	/**
	 * This method lets all bots quit from the network they're connected to.
	 */
	public void shutdown () {
		for (IrcBot pBot : m_pBots) {
			pBot.out.quit ("Bot has been shutdown via terminal.");
		}
	}
	
	/**
	 * The BotManager runs in a seperate thread, for performance reasons.
	 * This is ugly code and needs fixing.
	 */
	public void run () {
		HashMap<String, String> config = ConfigManager.getModule ("Main");
		
		//String serverName = config.get ("servername");
		String ircHost = config.get("ircserver");
		int ircPort    = Integer.parseInt(config.get("ircport"));
		
		int numBots            = Integer.parseInt(config.get("numbots"));
		
		String[] botNames      = config.get("botnames").split(",");
		String botIdent        = config.get("botident");
		String botRealname     = "GoldenAK v2 by MrBondt";
		
		String bindHost = config.get ("bindhost");
		int bindPort    = Integer.parseInt (config.get ("bindport"));
		
		for (int i = 0; i < numBots; i++) {
			IrcBot pBot = new IrcBot ();
			pBot.setNickname (botNames [i]);
			pBot.setUsername (botIdent);
			pBot.setRealname (botRealname);
			
			// FIXME when multi-server is implemented properly.
			pBot.setSlave (i == 0 ? false : true);
			
			try {
				if (!bindHost.equals ("")) {
					pBot.bind (bindHost, bindPort);
				}
				
				pBot.connect (ircHost, ircPort);
			} catch (Exception ex) {
				System.out.println("Error in connect() bot ID " + i + ": " +
					ex.getMessage());
				continue;
			}
			
			m_pBots.addBot (pBot);
		}
		
		boolean bRun = true;
		
		while (bRun) {
			for (IrcBot pBot : m_pBots) {
				try {
					pBot.loop ();
				} catch (IOException pException) {
					System.out.println (pBot.getNickname () + " lost connection to server " + pBot.getServerName ());
					
					m_pBots.removeBot (pBot);
					// Because the removeBot() method breaks the iterator,
					// we're going to break the for-loop.
					break;
				} catch (Exception pException) {
					System.out.println("Error in loop() with bot " +
						pBot.getNickname () + ": " + pException);
					pException.printStackTrace();
				}
			}
			
			if (m_pBots.numBots () == 0) {
				bRun = false;
			}
		}
		
		// If we get here, shut down the bot.
		ModuleManager.getInstance ().disable ();
	}
}